package intranet.client;
import intranet.client.DataBaseService;
import intranet.client.DataBaseServiceAsync;
import intranet.client.Session;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DecoratedPopupPanel;
import com.google.gwt.user.client.ui.DecoratedStackPanel;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;


/**
 * Tab visible seulement chez les chefs de filières et le coordinateur.
 * Chaque chef de filière aura acces qu'à la fillière dont il est responsable
 * Le coordinateur a une vue plus élargie car il a accès à toutes filières
 */
public class SimulatorTab extends VerticalPanel {
	
	//retour de la requete.
	HashMap<String, String[]> subjectHashMap;
	HashMap<String, String[]> currentHashMap = new HashMap<String, String[]>();
	
	private static final String SERVER_ERROR = "An error occurred while " +
			"attempting to contact the server. Please check your network " +
	 		"connection and try again.";
	private final DataBaseServiceAsync dataService = GWT.create(DataBaseService.class);
	private final TemplatesTabFuncAsync templatesFunc = GWT.create(TemplatesTabFunc.class);

	//Statut du coordinateur des enseignements.
	private final String ADMIN_ID = "0";
	
	HashMap<String, String[]> courseHM = new HashMap<String, String[]>();
	HashMap<String, String[]> subjectHM = new HashMap<String, String[]>();
	HashMap<String, String[]> teacherHM = new HashMap<String, String[]>();
	HashMap<String, String[]> teacherSubjectHM = new HashMap<String, String[]>();
	HashMap<String, String[]> subjectCourseHM = new HashMap<String, String[]>();
	
	ArrayList<String> subjectList = new ArrayList<String>();
	ArrayList<String> teacherList = new ArrayList<String>();
	ArrayList<String> createdTupleList = new ArrayList<String>(); 
	ArrayList<String> modifiedTupleList = new ArrayList<String>();
	
	protected Session s;
	protected String userStatus;
	
	ScrollPanel mainPanel;
	VerticalPanel insidePanel;
	HorizontalPanel topPanel;
	HorizontalPanel horizPanel;
	VerticalPanel teacherPanel;
	VerticalPanel coursePanel = new VerticalPanel();
	

	MultiWordSuggestOracle oracleTeacher = new MultiWordSuggestOracle();
	MultiWordSuggestOracle oracleSubject = new MultiWordSuggestOracle();
	
	
	//Panel qui contient les matières pour chaque enseignant
	VerticalPanel teacherSubjPanel = new VerticalPanel();
	
	//Panel qui contient les enseignants pour chaque matière
	VerticalPanel subjectTeachPanel = new VerticalPanel();
	
	DecoratedStackPanel courseStackPanel = new DecoratedStackPanel();
	
	//Booleens de vue
	Boolean viewSubject = false;
	Boolean firstViewSubject = false;
	Boolean firstViewTeacher = false;
	Boolean firstView = true;
	Boolean firstIter = true;
	
	//Pour mémoire lors d'appel du pop-up à partir des SuggestBoxes
	String lastTeacherSelected = "";
	String lastSubjectSelected = "";
	
	
	//Menu
	protected MenuItem menuSwitch, menuRestart , menuExport, menuValid;
	protected Command cmdSwitch, cmdCopy, cmdDisplay, cmdRestart, cmdExport, cmdExport2, cmdValid;
	protected MenuBar menu, insideMenu;

	
	//Contenant des enseignants dans le stackPanel
	VerticalPanel teachersPanel;
	
	//Contenant les professeurs enseignants la matière dans subjectTeachStackPanel
	VerticalPanel teachingPanel;
	//Contenant les professeurs qui peuvent enseigner la matière dans subjectTeachStackPanel
	VerticalPanel canTeachPanel;
	//Contenant les autres enseigants dans subjectTeachStackPanel
	VerticalPanel otherTeacherPanel;
	
	//Contenant les matières enseignées par l'enseignant dans teacherSubjStackPanel
	VerticalPanel taughtSubjectPanel;
	//Contenant les matières pouvant être enseignées par l'enseignant dans teacherSubjStackPanel
	VerticalPanel canBeTaughtSubjectPanel;
	//Contenant les matières non-enseignées par l'enseignant dans teacherSubjStackPanel
	VerticalPanel otherSubjectPanel;
	
	
	DecoratedStackPanel teacherStackPanel;
	DecoratedStackPanel subjectStackPanel;
	DecoratedStackPanel teacherSubjStackPanel;
	DecoratedStackPanel subjectTeachStackPanel;
	
	//HTML de la fiche à générer
	HTML document;
	
	/**
	 * Fonction pour la génération des HashMap à partir de la base de données.
	 */
	@SuppressWarnings("unchecked")
	public void dataBaseLoad(){
		 
		//Génération du HashMap courseHM
		String sessionReq = "SELECT * FROM course ORDER BY course_name";
		dataService.select(sessionReq, new AsyncCallback<HashMap<String,String[]>>(){
			public void onSuccess(HashMap<String, String[]> result){
				courseHM = (HashMap<String, String[]>) result.clone();
				
				//Génération du HashMap subjectHM
				String sessionReq = "SELECT * FROM subject ORDER BY subject_name";
				dataService.select(sessionReq, new AsyncCallback<HashMap<String,String[]>>(){
					public void onSuccess(HashMap<String, String[]> result){
						subjectHM = (HashMap<String, String[]>) result.clone();
						
				        //Génération du HashMap teacherHM
				        String sessionReq = "SELECT teacher_login, teacher_name, teacher_firstname, teacher_status,teacher_quota FROM teacher ORDER BY teacher_name, teacher_firstname";
				        dataService.select(sessionReq, new AsyncCallback<HashMap<String,String[]>>(){
							public void onFailure(Throwable caught){
								Window.alert("Erreur lors du chargement des enseignants dans la base de données");
								
							}

							public void onSuccess(HashMap<String, String[]> result){
								teacherHM = (HashMap<String, String[]>) result.clone();
								
								//Génération du HashMap teacherSubjectHM
						        currentHashMap.clear();
						        String sessionReq = "Select * from teacher_subject";
						        dataService.select(sessionReq, new AsyncCallback<HashMap<String,String[]>>(){
									public void onFailure(Throwable caught){
										
									}

									public void onSuccess(HashMap<String, String[]> result){
										teacherSubjectHM = (HashMap<String, String[]>) result.clone();
										
										//Génération du HashMap subjectCourseHM
								        currentHashMap.clear();
								        String sessionReq = "Select * from subject_course";
								        dataService.select(sessionReq, new AsyncCallback<HashMap<String,String[]>>(){
											public void onFailure(Throwable caught){
												
											}

											public void onSuccess(HashMap<String, String[]> result){
												subjectCourseHM = (HashMap<String, String[]>) result.clone();
												if (firstView){
													simulatorTabNext();
												}
											}
										});
									}
								});
							}
						});
					}
					public void onFailure(Throwable caught){
					}
				});
				
			}
			public void onFailure(Throwable caught){
				//Window.alert("Erreur lors du chargement de la base de données");
			}
		});
	}
	/**
	 * Constructeur
	 * @param sess Les informations de la session ouverte
	 */
	public SimulatorTab(Session sess){
		s=sess;
		//Chargement des informations de la base de données
		dataBaseLoad();
	}
	
	/**
	 * Fonction pour créer l'interface graphique de l'onglet Bac à Sable
	 */
	public void simulatorTabNext(){
		
		userStatus = s.get("teacher_status");
		for(int i=courseHM.get("course_id").length-1; i>=0; i--){
			if (!courseHM.get("course_id")[i].equals(userStatus) && !userStatus.equals(ADMIN_ID)){
				courseHM = removeALine(courseHM, i);
			}
		}

		
		mainPanel = new ScrollPanel();
		insidePanel = new VerticalPanel();
		topPanel = new HorizontalPanel();
		horizPanel = new HorizontalPanel();
		
		
		teacherPanel = new VerticalPanel();
	    teacherStackPanel = new DecoratedStackPanel();
	    teacherStackPanel.setWidth("200px");
	    teachersPanel = new VerticalPanel();
		teacherStackPanel.add(teachersPanel, "Enseignants", true);
		teacherPanel.add(teacherStackPanel);
		
		teacherPanel.setVisible(!viewSubject);
		coursePanel.setVisible(viewSubject);

		teacherSubjStackPanel = new DecoratedStackPanel();
		teacherSubjStackPanel.setWidth("200px");
	    taughtSubjectPanel = new VerticalPanel();
	    canBeTaughtSubjectPanel = new VerticalPanel();
	    otherSubjectPanel = new VerticalPanel();
		teacherSubjStackPanel.add(taughtSubjectPanel, "Matières enseignées", true);
		teacherSubjStackPanel.add(canBeTaughtSubjectPanel, "Matières pouvant être enseignées", true);
		teacherSubjStackPanel.add(otherSubjectPanel, "Autres matières", true);
		
		final SuggestBox teacherSubjSuggestBox = new SuggestBox(oracleSubject);
		teacherSubjSuggestBox.setText("Chercher matière");
		teacherSubjSuggestBox.setWidth("190px");
		teacherSubjSuggestBox.getTextBox().addFocusHandler(new FocusHandler(){
			public void onFocus(FocusEvent event) {
				teacherSubjSuggestBox.getTextBox().setSelectionRange(0,teacherSubjSuggestBox.getTextBox().getText().length());
				
			}
		});
		teacherSubjPanel.add(teacherSubjSuggestBox);
		
		teacherSubjPanel.add(teacherSubjStackPanel);
		teacherSubjPanel.setVisible(viewSubject && firstViewTeacher);
		
		subjectTeachStackPanel = new DecoratedStackPanel();
		subjectTeachStackPanel.setWidth("200px");
	    teachingPanel = new VerticalPanel();
	    canTeachPanel = new VerticalPanel();
	    otherTeacherPanel = new VerticalPanel();
	    subjectTeachStackPanel.add(teachingPanel, "Professeurs l'enseignant", true);
	    subjectTeachStackPanel.add(canTeachPanel, "Professeurs pouvant l'enseigner", true);
	    subjectTeachStackPanel.add(otherTeacherPanel, "Autres professeurs ", true);
		final SuggestBox subjectTeachSuggestBox = new SuggestBox(oracleTeacher);
		subjectTeachSuggestBox.setText("Chercher un nom");
		subjectTeachSuggestBox.getTextBox().addFocusHandler(new FocusHandler(){
			public void onFocus(FocusEvent event) {
				subjectTeachSuggestBox.getTextBox().setSelectionRange(0,subjectTeachSuggestBox.getTextBox().getText().length());
				
			}
		});
		subjectTeachSuggestBox.setWidth("190px");
		subjectTeachPanel.add(subjectTeachSuggestBox);
	    subjectTeachPanel.add(subjectTeachStackPanel);
	    subjectTeachPanel.setVisible(!viewSubject && firstViewSubject);
		


		horizPanel.add(teacherPanel);
		horizPanel.add(coursePanel);
		horizPanel.add(teacherSubjPanel);
		horizPanel.add(subjectTeachPanel);
		
		createMenuBar(insidePanel);
		insidePanel.add(horizPanel);
		mainPanel.setSize(Window.getClientWidth()*3/4+"px", Window.getClientHeight()+"px");
		mainPanel.add(insidePanel);
		
		teacherSubjSuggestBox.getTextBox().addKeyPressHandler(new KeyPressHandler(){
			public void onKeyPress(KeyPressEvent event){
				Widget source = (Widget) event.getSource();
	            int left = source.getAbsoluteLeft() + 40;
	            int top = source.getAbsoluteTop() - 30;
				if (event.getNativeEvent().getKeyCode()==KeyCodes.KEY_ENTER){
					String subject = teacherSubjSuggestBox.getValue();
					if (subjectList.contains(subject)){
						generatePopUp(lastTeacherSelected, subject);
					}
					else{
						final DecoratedPopupPanel simplePopup = new DecoratedPopupPanel(true);
						simplePopup.setWidget(new HTML("Nom incorrect"));

			            simplePopup.setPopupPosition(left, top);
			            simplePopup.show();
					}
				}
			}
		});
		
		subjectTeachSuggestBox.getTextBox().addKeyPressHandler(new KeyPressHandler(){
			public void onKeyPress(KeyPressEvent event){
				Widget source = (Widget) event.getSource();
				int left = source.getAbsoluteLeft() + 40;
	            int top = source.getAbsoluteTop() - 30;
	            String teacherLogin = "";
				if (event.getNativeEvent().getKeyCode()==KeyCodes.KEY_ENTER){
					String teacher = subjectTeachSuggestBox.getValue();
					for (int i=0; i<teacherHM.get("teacher_login").length; i++){
						if ((teacherHM.get("teacher_firstname")[i]+" "+teacherHM.get("teacher_name")[i]).equals(teacher))
							teacherLogin = teacherHM.get("teacher_login")[i];
					}
					if (teacherList.contains(teacher)){
						generatePopUp(teacherLogin, lastSubjectSelected);
					}
					else{
						final DecoratedPopupPanel simplePopup = new DecoratedPopupPanel(true);
						simplePopup.setWidget(new HTML("Nom incorrect"));

			            simplePopup.setPopupPosition(left, top);
			            simplePopup.show();
					}

				}
			}
		});
		
		generateCourses();
		generateTeachers();
		
		if (firstView){
			this.add(mainPanel);
		}
	}
	
	/**
	 * Fonction qui génère la barre de menu
	 * @param panel
	 */
	public void createMenuBar(VerticalPanel panel){
		insideMenu = new MenuBar(true);
		insideMenu.setAutoOpen(false);
		insideMenu.setAnimationEnabled(true);
		

		
		
        menu = new MenuBar(false);
        menu.setAutoOpen(false);
        menu.setWidth("100%");
        menu.setAnimationEnabled(true);
        
        
        //Commande pour l'inversion des vues
        cmdSwitch = new Command(){
			public void execute(){
				if (firstIter){
					firstIter=false;
				}
				else{
					viewSubject=!viewSubject;
				}
	    		teacherPanel.setVisible(viewSubject);
	    		teacherSubjPanel.setVisible(viewSubject && firstViewTeacher);
	    		coursePanel.setVisible(!viewSubject);
	    		subjectTeachPanel.setVisible(!viewSubject && firstViewSubject);
			}
		};
		
		
		 //Commande pour effacer toutes les modifications effectuées
		cmdRestart = new Command(){
			public void execute(){
				refresh();
		        viewSubject=false;
		    	unboldElements(teachersPanel);
	    		teacherPanel.setVisible(viewSubject);
	    		coursePanel.setVisible(!viewSubject);
		        firstViewTeacher = false;
		        firstViewSubject = false;
	    		teacherSubjPanel.setVisible(false);
	    		subjectTeachPanel.setVisible(false);
			}
		};
		
		 //Commande pour l'exportation
		cmdExport = new Command(){
			public void execute(){
				
				exportation(courseHM.get("course_id")[0]);
			}
		};
		//Commande pour l'exportation
		cmdExport2 = new Command(){
			public void execute(){
				for(int i=courseHM.get("course_id").length; i>=0; i--){
					exportation(courseHM.get("course_id")[i]);
				}
			}
		};
		 //Commande executé par le menu save
		cmdValid = new Command(){
			public void execute(){
				final DialogBox validationConfirmation = new DialogBox(false);
				validationConfirmation.setAnimationEnabled(true);
				validationConfirmation.setGlassEnabled(true);
				validationConfirmation.setText("Confirmation de la validation");
				VerticalPanel panel = new VerticalPanel();
				//HorizontalPanel textPanel = new HorizontalPanel();
				HorizontalPanel buttonPanel = new HorizontalPanel();
				Label text = new Label("Êtes vous sûr de vouloir apporter les modifications sur la base de données?");
				
				Button okButton = new Button ("OK");
				Button cancelButton = new Button("Annuler");
				buttonPanel.add(cancelButton);
				buttonPanel.add(okButton);
				buttonPanel.setHorizontalAlignment(ALIGN_CENTER);
				panel.add(text);
				panel.add(buttonPanel);
				
				cancelButton.addClickHandler(new ClickHandler(){
					public void onClick(ClickEvent event){
						validationConfirmation.hide();
					}
				});
				okButton.addClickHandler(new ClickHandler(){
					public void onClick(ClickEvent event){
						updateDB();
						refresh();
				        viewSubject=false;
				    	unboldElements(teachersPanel);
			    		teacherPanel.setVisible(viewSubject);
			    		coursePanel.setVisible(!viewSubject);
				        firstViewTeacher = false;
				        firstViewSubject = false;
			    		teacherSubjPanel.setVisible(false);
			    		subjectTeachPanel.setVisible(false);
						validationConfirmation.hide();
					}
				});
				
				validationConfirmation.add(panel);
				validationConfirmation.center();
				validationConfirmation.show();
			}
		};
		
        
        menuSwitch = menu.addItem("Inverser", cmdSwitch);
        menuRestart = menu.addItem("Recommencer", cmdRestart);
        //menuExport = menu.addItem("Exporter", cmdExport);
        
		if (userStatus.equals(ADMIN_ID)){
			insideMenu.addItem("tous", cmdExport2);
			for (int i=0; i<courseHM.get("course_id").length; i++){
				final int index = i;
				insideMenu.addItem(courseHM.get("course_name")[i], new Command(){
					public void execute(){
						exportation(courseHM.get("course_id")[index]);
					}
				});
			}
			menuExport = menu.addItem("Exporter", insideMenu);
		}
		else{
			menuExport = menu.addItem("Exporter", cmdExport);
		}
        
        menuValid = menu.addItem("Valider",cmdValid);
		if (!userStatus.equals(ADMIN_ID)){
			menuValid.setVisible(false);
		}
        panel.add(menu);
	}
	
	/**
	 * Méthode qui enlève les balises <b></b> dans le code HTML de l'élément en gras.
	 * @param vp Panel qui contient l'élément gras.
	 */
	public void unboldElements(VerticalPanel vp) {
		for (int i =0; i<vp.getWidgetCount(); i++){
			HTML m = (HTML)vp.getWidget(i);
			if (isBolded(m)){
				int size = m.getHTML().length();
				m.setHTML(m.getHTML().substring(3, size-4));
			}
		}
	}
	
	/**
	 * Fonction qui génère les filières et les matières qui les composent.
	 */
	private void generateCourses() {
		courseStackPanel.setWidth("200px");
		for (int j=0; j<courseHM.get("course_name").length; j++){
				VerticalPanel course = new VerticalPanel();
				if (firstView){
					courseStackPanel.add(course, courseHM.get("course_name")[j], true);
				}
				generateSubjects(course, courseHM.get("course_id")[j]);
		}
		coursePanel.add(courseStackPanel);
	}
	
	/**
	 * Méthode qui génère les matières à l'intérieur d'une filière donnée.
	 * @param course Panel contenant les filières
	 * @param courseId Nom de la filière
	 */
	public void generateSubjects(final VerticalPanel course, String courseId){
		for (int j=0; j<subjectCourseHM.get("subject_id").length; j++){
		    //Ajout des matières dans le textfield de suggestions
			String subjectName = "";
			for (int i = 0; i<subjectHM.get("subject_id").length; i++){
				if (subjectHM.get("subject_id")[i].equals(subjectCourseHM.get("subject_id")[j]))
					subjectName = subjectHM.get("subject_name")[i];
			}
			if (!subjectList.contains(subjectName)){
				subjectList.add(subjectName);
				oracleSubject.add(subjectName);
			}
			if (subjectCourseHM.get("course_id")[j].equals(courseId)){
				final HTML subject = new HTML(subjectName);
				final String subjectNameBis = subjectName;
				
				subject.addClickHandler(new ClickHandler(){
					public void onClick(ClickEvent event){
						unboldElements(course);
						lastSubjectSelected = subjectNameBis;
						subject.setHTML("<b>"+subject.getText()+"</b>");
						firstViewSubject = true;
						subjectTeachPanel.setVisible(firstViewSubject);
						generateTeacherPanels(subjectNameBis);
					}
				});
				course.add(subject);
			}
		}
	}
	
	/**
	 * Méthode qui génère la liste des enseignants enseignant ou non une matière donnée
	 * @param subject_name Nom de la matière
	 */
	public void generateTeacherPanels(String subject_name){
		teachingPanel.clear();
		canTeachPanel.clear();
		otherTeacherPanel.clear();
		List<String> isIn = new ArrayList<String>();
		List<String> canBe = new ArrayList<String>();
		List<String> isOut = new ArrayList<String>();
		
		String subjectId="";
		for (int i = 0; i<subjectHM.get("subject_id").length; i++){
			if (subjectHM.get("subject_name")[i].equals(subject_name))
				subjectId = subjectHM.get("subject_id")[i];
		}
		for (int j=0; j<teacherSubjectHM.get("subject_id").length; j++){
			//Cas où l'enseignant enseigne ou peut enseigner la matière
			if(teacherSubjectHM.get("subject_id")[j].equals(subjectId)){
				//Cas où l'enseignant peut enseigner
				if (teacherSubjectHM.get("teacher_subject_cm")[j].equals("0")
						&& teacherSubjectHM.get("teacher_subject_td")[j].equals("0")
						&& teacherSubjectHM.get("teacher_subject_tp")[j].equals("0")){
					isOut.remove(teacherSubjectHM.get("teacher_login")[j]);
					isIn.remove(teacherSubjectHM.get("teacher_login")[j]);
					canBe.add(teacherSubjectHM.get("teacher_login")[j]);
				}
				//Cas où l'enseignant enseigne la matière
				else{
					isOut.remove(teacherSubjectHM.get("teacher_login")[j]);
					canBe.remove(teacherSubjectHM.get("teacher_login")[j]);
					isIn.add(teacherSubjectHM.get("teacher_login")[j]);	
				}
			}
			//Cas où l'enseigant est étranger à la matière
			else{
				if (!isOut.contains(teacherSubjectHM.get("teacher_login")[j])
						&& !isIn.contains(teacherSubjectHM.get("teacher_login")[j])
						&& !canBe.contains(teacherSubjectHM.get("teacher_login")[j]))
					isOut.add(teacherSubjectHM.get("teacher_login")[j]);
			}
		}
		for (int i = 0; i<teacherHM.get("teacher_login").length; i++){
		    //Ajout des enseignants dans le textfield de suggestions
			String teacherName = teacherHM.get("teacher_firstname")[i]+" "+teacherHM.get("teacher_name")[i];
			if (!teacherList.contains(teacherName)){
				teacherList.add(teacherName);
				oracleTeacher.add(teacherName);
			}
			if (!isIn.contains(teacherHM.get("teacher_login")[i])
					&& !canBe.contains(teacherHM.get("teacher_login")[i])
					&& !isOut.contains(teacherHM.get("teacher_login")[i])){
				isOut.add(teacherHM.get("teacher_login")[i]);
			}
		}
		//Ajout dans teachingPanel
		final String subject = subject_name;
		for (final String login : isIn){
			String name = fromLoginToName(login);
			final HTML html = new HTML(name);
			html.addClickHandler(new ClickHandler(){
			      public void onClick(ClickEvent event){
			    	  unboldElements(teachingPanel);
			    	  html.setHTML("<b>"+html.getText()+"</b>");
			    	  generatePopUp(login, subject);
			      }
			});
			teachingPanel.add(html);
		}
		//Ajout dans canTeachPanel
		for (final String login : canBe){
			String name = fromLoginToName(login);
			final HTML html = new HTML(name);
			html.addClickHandler(new ClickHandler(){
				public void onClick(ClickEvent event){
					unboldElements(canTeachPanel);
					html.setHTML("<b>"+html.getText()+"</b>");
					generatePopUp(login, subject);
				}
			});
			canTeachPanel.add(html);
		}
		//Ajout dans otherTeacherPanel
		for (final String login : isOut){
			String name = fromLoginToName(login);
			final HTML html = new HTML(name);
			html.addClickHandler(new ClickHandler(){
				public void onClick(ClickEvent event){
					unboldElements(otherTeacherPanel);
					html.setHTML("<b>"+html.getText()+"</b>");
					generatePopUp(login, subject);
				}
			});
			otherTeacherPanel.add(html);
		}
	}
	
	/**
	 * Méthode qui génère les enseignants dans teacherPanel
	 */
	public void generateTeachers(){
		if (firstView){
			for (int j=0; j<teacherHM.get("teacher_login").length; j++){
				final HTML teacher = new HTML(fromLoginToName(teacherHM.get("teacher_login")[j]));
				final int jbis = j;
				teacher.addClickHandler(new ClickHandler(){
					public void onClick(ClickEvent event){
						unboldElements(teachersPanel);
						String teacherLogin = teacherHM.get("teacher_firstname")[jbis].charAt(0)+teacherHM.get("teacher_name")[jbis];
						teacherLogin = teacherLogin.toLowerCase();
						lastTeacherSelected = teacherLogin;
						teacher.setHTML("<b>"+teacher.getText()+"</b>");
						firstViewTeacher = true;
						teacherSubjPanel.setVisible(firstViewTeacher);
						generateSubjectPanels(teacherHM.get("teacher_login")[jbis]);
					}
				});
				teachersPanel.add(teacher);
			}
		}
	}
	
	
	/**
	 * Méthode qui détermine si une matière doit être affichée en fonction de l'utilisateur
	 * @param subjectId Identifiant de la matièere
	 */
	public boolean isInCourse(String subjectId){
		boolean result=false;
		String courseId = "";
		for (int i = 0; i<subjectCourseHM.get("subject_id").length; i++){
			if (subjectCourseHM.get("subject_id")[i].equals(subjectId))
				courseId = subjectCourseHM.get("course_id")[i];
		}
		if (userStatus.equals(ADMIN_ID) || userStatus.equals(courseId)){
			result = true;
		}
		return result;
	}
	
	/**
	 * Méthode qui génère la liste des matières enseignées ou non pour chaque enseignant
	 * @param teacher_login Identifiant de l'enseignant
	 */
	public void generateSubjectPanels(String teacher_login){
		taughtSubjectPanel.clear();
		canBeTaughtSubjectPanel.clear();
		otherSubjectPanel.clear();
		List<String> isIn = new ArrayList<String>();
		List<String> canBe = new ArrayList<String>();
		List<String> isOut = new ArrayList<String>();
		final String login = teacher_login;
		for (int j=0; j<teacherSubjectHM.get("teacher_login").length; j++){
			//Cas où la matière est enseignée ou peut être enseignée par l'enseignant sélectionné
			if(teacherSubjectHM.get("teacher_login")[j].equals(teacher_login)
					&& isInCourse(teacherSubjectHM.get("subject_id")[j])){
				String k = teacherSubjectHM.get("subject_id")[j];
				String subjectName="";
				for (int i = 0; i<subjectHM.get("subject_id").length; i++){
					if (subjectHM.get("subject_id")[i].equals(k))
						subjectName = subjectHM.get("subject_name")[i];
				}
				//Cas où l'enseignant est dans la capacité d'enseigner la matière
				if (teacherSubjectHM.get("teacher_subject_cm")[j].equals("0")
						&& teacherSubjectHM.get("teacher_subject_td")[j].equals("0")
						&& teacherSubjectHM.get("teacher_subject_tp")[j].equals("0")){
					isOut.remove(subjectName);
					isIn.remove(subjectName);
					canBe.add(subjectName);
				}
				//Cas où l'enseignant enseigne la matière
				else{
					isOut.remove(subjectName);
					canBe.remove(subjectName);
					isIn.add(subjectName);	
				}
			}
			//Cas où la matière n'est pas enseignée
			else if (isInCourse(teacherSubjectHM.get("subject_id")[j])){
				String k =teacherSubjectHM.get("subject_id")[j];
				String subject="";
				for (int i = 0; i<subjectHM.get("subject_id").length; i++){
					if (subjectHM.get("subject_id")[i].equals(k))
						subject = subjectHM.get("subject_name")[i];
				}
				if (!isOut.contains(subject)
						&& !isIn.contains(subject)
						&& !canBe.contains(subject))
					isOut.add(subject);
			}
		}
		for (int i = 0; i<subjectHM.get("subject_name").length; i++){
			if (!isIn.contains(subjectHM.get("subject_name")[i])
					&& !canBe.contains(subjectHM.get("subject_name")[i])
					&& !isOut.contains(subjectHM.get("subject_name")[i])
					&& isInCourse(subjectHM.get("subject_id")[i]))
				isOut.add(subjectHM.get("subject_name")[i]);
		}
		//Ajout dans taughtSubjectPanel
		for (final String subject : isIn){
			final HTML html = new HTML(subject);
			html.addClickHandler(new ClickHandler(){
				public void onClick(ClickEvent event){
					unboldElements(taughtSubjectPanel);
					html.setHTML("<b>"+html.getText()+"</b>");
					generatePopUp(login, subject);
				}
			});
			taughtSubjectPanel.add(html);
		}
		//Ajout dans otherSubjectPanel
		for (final String subject : canBe){
			final HTML html = new HTML(subject);
			html.addClickHandler(new ClickHandler(){
				public void onClick(ClickEvent event){
					unboldElements(canBeTaughtSubjectPanel);
					html.setHTML("<b>"+html.getText()+"</b>");
					generatePopUp(login, subject);
				}
			});
			canBeTaughtSubjectPanel.add(html);
		}
		//Ajout dans otherSubjectPanel
		for (final String subject : isOut){
			final HTML html = new HTML(subject);
			html.addClickHandler(new ClickHandler(){
				public void onClick(ClickEvent event){
					unboldElements(otherSubjectPanel);
					html.setHTML("<b>"+html.getText()+"</b>");
					generatePopUp(login, subject);
				}
			});
			otherSubjectPanel.add(html);
		}
	}

	/**
	 * Méthode qui génère la fenêtre de dialogue avec le nombre d'heures
	 * @param login Identifiant de l'enseignant
	 * @param subjectName Nom de la matière
	 */
	public void generatePopUp(String login, String subjectName){
		final DialogBox popUp = new DialogBox(false);
		popUp.setAnimationEnabled(true);
		popUp.setGlassEnabled(true);
		popUp.setText(fromLoginToName(login)+" - "+subjectName);
		VerticalPanel panel = new VerticalPanel();
		HorizontalPanel buttonPanel = new HorizontalPanel();
		final String[] actualValues = new String[3];
		
		Label type = new Label("");
		Label cm = new Label("CM");
		Label td = new Label("TD");
		Label tp = new Label("TP");
		Grid grid = new Grid(4,5);
		grid.setBorderWidth(1);
		
		
		grid.setWidget(0, 0, type);
		grid.setWidget(1, 0, cm);
		grid.setWidget(2, 0, td);
		grid.setWidget(3, 0, tp);

		Label numberOfGroups = new Label("Nombre de groupes");
		grid.setWidget(0, 1, numberOfGroups);
		Label remainingHSubject = new Label("Reste à attribuer Matière");
		grid.setWidget(0, 2, remainingHSubject);
		Label remainingHTeacher = new Label("Reste à attribuer Enseignant");
		grid.setWidget(0, 3, remainingHTeacher);
		Label attribution = new Label("Attribution");
		grid.setWidget(0, 4, attribution);
		
		for (int i=0; i<=4; i++){
			grid.getWidget(0, i).setStylePrimaryName("tableHead");
			if (i==0){
				grid.getWidget(0, i).setWidth("35px");
			}
			else{
				grid.getWidget(0, i).setWidth("100px");
			}
		}
		for (int i=1; i<=3; i++){
			grid.getWidget(i, 0).setStylePrimaryName("tableHead");
		}
		
		//Labels qui contiennent le nombre d'heures restantes à attribuer
		//pour une matière.
		final Label shCM = new Label("");
		final Label shTD = new Label("");
		final Label shTP = new Label("");
		//Labels qui contiennent le nombre d'heures restantes à attribuer
		//pour un enseignant.
		final Label thCM = new Label("");
		final Label thTD = new Label("");
		final Label thTP = new Label("");
		
		final ValidIntegerTextBox cmtx = new ValidIntegerTextBox();
		cmtx.setWidth("90px");
		final ValidIntegerTextBox tdtx = new ValidIntegerTextBox();
		tdtx.setWidth("90px");
		final ValidIntegerTextBox tptx = new ValidIntegerTextBox();
		tptx.setWidth("90px");
		
		Label subject_group_cm = new Label("");
		Label subject_group_td = new Label("");
		Label subject_group_tp = new Label("");
		
		Button cancelButton = new Button("Annuler");
		Button okButton = new Button("OK");
		
		grid.setWidget(1, 1, subject_group_cm);
		grid.setWidget(2, 1, subject_group_td);
		grid.setWidget(3, 1, subject_group_tp);
		grid.setWidget(1, 2, shCM);
		grid.setWidget(2, 2, shTD);
		grid.setWidget(3, 2, shTP);
		grid.setWidget(1, 3, thCM);
		grid.setWidget(2, 3, thTD);
		grid.setWidget(3, 3, thTP);
		grid.setWidget(1, 4, cmtx);
		grid.setWidget(2, 4, tdtx);
		grid.setWidget(3, 4, tptx);
		
		String subjectId = "";
		//L'index 'index' reste à -1 si l'enseignant est étranger à la matière
		int index = -1;
		for (int i = 0; i<subjectHM.get("subject_id").length; i++){
			if (subjectHM.get("subject_name")[i].equals(subjectName)){
				subjectId = subjectHM.get("subject_id")[i];
				subject_group_cm.setText(subjectHM.get("subject_group_cm")[i]);
				subject_group_td.setText(subjectHM.get("subject_group_td")[i]);
				subject_group_tp.setText(subjectHM.get("subject_group_tp")[i]);
			}
		}
		for (int i = 0; i<teacherSubjectHM.get("subject_id").length; i++){
			if (teacherSubjectHM.get("subject_id")[i].equals(subjectId)
					&& teacherSubjectHM.get("teacher_login")[i].equals(login))
				index = i;
		}
		
		if(index!=-1){
			cmtx.setValue(teacherSubjectHM.get("teacher_subject_cm")[index]);
			tdtx.setValue(teacherSubjectHM.get("teacher_subject_td")[index]);
			tptx.setValue(teacherSubjectHM.get("teacher_subject_tp")[index]);
			actualValues[0] = (teacherSubjectHM.get("teacher_subject_cm")[index]);
			actualValues[1] = (teacherSubjectHM.get("teacher_subject_td")[index]);
			actualValues[2] = (teacherSubjectHM.get("teacher_subject_tp")[index]);
		}
		else{
			cmtx.setValue("");
			tdtx.setValue("");
			tptx.setValue("");
			actualValues[0] = "";
			actualValues[1] = "";
			actualValues[2] = "";
		}
		
		//Différence entre le nombre d'heures à faire et le nombre d'heures déjà
		//attribuées par matière
		double[] remainingHoursSubject = new double[3];
		remainingHoursSubject = remainingHoursSubject(subjectId);
		shCM.setText(""+remainingHoursSubject[0]);
		shTD.setText(""+remainingHoursSubject[1]);
		shTP.setText(""+remainingHoursSubject[2]);
		
		//Différence entre le nombre d'heures à faire et le nombre d'heures déjà
		//attribuées par enseignant
		double[] remainingHoursTeacher = new double[3];
		remainingHoursTeacher = remainingHoursTeacher(login);
		thCM.setText(""+remainingHoursTeacher[0]);
		thTD.setText(""+remainingHoursTeacher[1]);
		thTP.setText(""+remainingHoursTeacher[2]);
		
		for (int i=1; i<4; i++){
			for (int j=2; j<4; j++){
				String hours = ((Label) grid.getWidget(i, j)).getText();
				if (Double.parseDouble(hours)<0.0){
					grid.getWidget(i, j).setStylePrimaryName("tableRed");
				}
				else{
					grid.getWidget(i, j).setStylePrimaryName("tableGreen");	
				}
			}
		}
		
		//Changement dynamique des champs
		FocusHandler fh = new FocusHandler(){
			String tempValues1 = actualValues[0];
			String tempValues2 = actualValues[1];
			String tempValues3 = actualValues[2];
			public void onFocus(FocusEvent event){
				//tout en temporaire
				double[] differences = new double[3];
				if ((!cmtx.getValue().equals(tempValues1)
						|| !tdtx.getValue().equals(tempValues2)
						|| !tptx.getValue().equals(tempValues3))){
					if (cmtx.getValue().equals("")){
						if (tempValues1.equals(""))
							differences[0] = 0.0;
						else differences[0] = Double.parseDouble(tempValues1);
					}
					else{
						if (tempValues1.equals(""))
							differences[0] = 0.0 - Double.parseDouble(cmtx.getValue());
						else differences[0] = Double.parseDouble(tempValues1) - Double.parseDouble(cmtx.getValue());
					}
					if (tdtx.getValue().equals("")){
						if (tempValues2.equals(""))
							differences[1] = 0.0;
						else differences[1] = Double.parseDouble(tempValues2);
					}
					else{
						if (tempValues2.equals(""))
							differences[1] = 0.0 - Double.parseDouble(tdtx.getValue());
						else differences[1] = Double.parseDouble(tempValues2) - Double.parseDouble(tdtx.getValue());
					}
					if (tptx.getValue().equals("")){
						if (tempValues3.equals(""))
							differences[2] = 0.0;
						else differences[2] = Double.parseDouble(tempValues3);
					}
					else{
						if (tempValues3.equals(""))
							differences[2] = 0.0 - Double.parseDouble(tptx.getValue());
						else differences[2] = Double.parseDouble(tempValues3) - Double.parseDouble(tptx.getValue());
					}
					
					shCM.setText(""+(Double.parseDouble(shCM.getText())+differences[0]));
					shTD.setText(""+(Double.parseDouble(shTD.getText())+differences[1]));
					shTP.setText(""+(Double.parseDouble(shTP.getText())+differences[2]));
					
					if (!cmtx.getValue().equals(tempValues1)){
						double value = Double.parseDouble(cmtx.getValue());
						double valueHEQTD = value*1.8333;
						double[] newTeacherHours = calculateHoursFromHEQTD(valueHEQTD);
						thCM.setText(""+(Double.parseDouble(thCM.getText())-newTeacherHours[0]));
						thTD.setText(""+(Double.parseDouble(thTD.getText())-newTeacherHours[1]));
						thTP.setText(""+(Double.parseDouble(thTP.getText())-newTeacherHours[2]));
					}
					else if (!tdtx.getValue().equals(tempValues2)){
						double[] newTeacherHours = calculateHoursFromHEQTD(Double.parseDouble(tdtx.getValue()));
						thCM.setText(""+(Double.parseDouble(thCM.getText())-newTeacherHours[0]));
						thTD.setText(""+(Double.parseDouble(thTD.getText())-newTeacherHours[1]));
						thTP.setText(""+(Double.parseDouble(thTP.getText())-newTeacherHours[2]));
					}
					else if (!tptx.getValue().equals(tempValues3)){
						double value = Double.parseDouble(cmtx.getValue());
						double valueHEQTD = value*1.8333;
						double[] newTeacherHours = calculateHoursFromHEQTD(valueHEQTD);
						thCM.setText(""+(Double.parseDouble(thCM.getText())-newTeacherHours[0]));
						thTD.setText(""+(Double.parseDouble(thTD.getText())-newTeacherHours[1]));
						thTP.setText(""+(Double.parseDouble(thTP.getText())-newTeacherHours[2]));
					}
					tempValues1 = cmtx.getValue();
					tempValues2 = tdtx.getValue();
					tempValues3 = tptx.getValue();
				}
			}
		};
		
		cmtx.addFocusHandler(fh);
		tdtx.addFocusHandler(fh);
		tptx.addFocusHandler(fh);
		
		//Bouton cancel: on enregistre rien.
		buttonPanel.add(cancelButton);
		cancelButton.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event){
				popUp.hide();
			}
		});
		//Bouton OK: on enregistre les modifications dans le hashMap, si modification il y a.
		buttonPanel.add(okButton);
		final int i = index;
		final String subjectId2 = subjectId;
		final String subjectName2 = subjectName;
		final String login2 = login;
		okButton.addClickHandler(new ClickHandler(){
			@SuppressWarnings("unchecked")
			public void onClick(ClickEvent event){
				/*
				 * Différents cas:
				 * matière étrangère et qqch à changé ->ajout +modif
				 * matière canBe et qqch changé->ajout + modif
				 * matière enseignée et qqch a changé->update
				 * matière enseignée et mise à zéro des compteurs->delete
				 */
				
				//Cas où pas de modifications et matière étrangère
				if (i==-1 && (cmtx.getValue().equals(actualValues[0]) &&
						tdtx.getValue().equals(actualValues[1]) &&
						tptx.getValue().equals(actualValues[2]))){
					//On ne fait rien et on ferme la boite de dialogue1
					generateSubjectPanels(login2);
					generateTeacherPanels(subjectName2);
				}
				//Cas où pas de modifications et matière enseignée ou pouvant être enseignée
				if (cmtx.getValue().equals(actualValues[0]) &&
						tdtx.getValue().equals(actualValues[1]) &&
						tptx.getValue().equals(actualValues[2])){
					//On ne fait rien et on ferme la boite de dialogue2
					generateSubjectPanels(login2);
					generateTeacherPanels(subjectName2);
				}
				//Cas où on retire toutes les heures attribuées à l'enseignant
				else if (cmtx.getValue().equals("0") &&
						tdtx.getValue().equals("0") &&
						tptx.getValue().equals("0")){
					HashMap<String, String> valuesToUpdate = new HashMap<String, String>();
					valuesToUpdate.put("subject_id", subjectId2);
					valuesToUpdate.put("teacher_login", login2);
					valuesToUpdate.put("teacher_subject_cm", cmtx.getValue());
					valuesToUpdate.put("teacher_subject_td", tdtx.getValue());
					valuesToUpdate.put("teacher_subject_tp", tptx.getValue());
					updateALine(teacherSubjectHM, i, valuesToUpdate);
					generateSubjectPanels(login2);
					generateTeacherPanels(subjectName2);
					if (!modifiedTupleList.contains(subjectId2+"/"+login2)){
						modifiedTupleList.add(subjectId2+"/"+login2);
					}
				}
				//Cas où on enlève une matière à un enseignant
				else if (cmtx.getValue().equals("") &&
						tdtx.getValue().equals("") &&
						tptx.getValue().equals("")){
					//Supression de la ligne 'index' dans le hashMap teacher_subject
					teacherSubjectHM = (HashMap<String, String[]>) removeALine(teacherSubjectHM, i).clone();
					generateSubjectPanels(login2);
					generateTeacherPanels(subjectName2);
					if (!modifiedTupleList.contains(subjectId2+"/"+login2)){
						modifiedTupleList.add(subjectId2+"/"+login2);
					}
				}
				
				else if (i != -1){
					String[] tS_cm = new String[teacherSubjectHM.get("subject_id").length];
					String[] tS_td = new String[teacherSubjectHM.get("subject_id").length];
					String[] tS_tp = new String[teacherSubjectHM.get("subject_id").length];
					tS_cm = teacherSubjectHM.get("teacher_subject_cm");
					tS_td = teacherSubjectHM.get("teacher_subject_td");
					tS_tp = teacherSubjectHM.get("teacher_subject_tp");
					if (cmtx.getValue()!=""){
						tS_cm[i]=cmtx.getValue();
					}
					else{
						tS_cm[i]="0";
					}
					if (tdtx.getValue()!=""){
						tS_td[i]=tdtx.getValue();
					}
					else{
						tS_td[i]="0";
					}
					if (tptx.getValue()!=""){
						tS_tp[i]=tptx.getValue();
					}
					else{
						tS_tp[i]="0";
					}
					teacherSubjectHM.put("teacher_subject_cm", tS_cm);
					teacherSubjectHM.put("teacher_subject_td", tS_td);
					teacherSubjectHM.put("teacher_subject_tp", tS_tp);
					generateSubjectPanels(login2);
					generateTeacherPanels(subjectName2);
					if (!modifiedTupleList.contains(subjectId2+"/"+login2)){
						modifiedTupleList.add(subjectId2+"/"+login2);
					}
				}
				else{
					if (cmtx.getValue().equals("")){
						cmtx.setValue("0");
					}
					if (tdtx.getValue().equals("")){
						tdtx.setValue("0");
					}
					if (tptx.getValue().equals("")){
						tptx.setValue("0");
					}
					//Ajout d'une ligne dans le hashMap teacher_subject
					HashMap<String, String> valuesToAdd = new HashMap<String, String>();
					valuesToAdd.put("subject_id", subjectId2);
					valuesToAdd.put("teacher_login", login2);
					valuesToAdd.put("teacher_subject_cm", cmtx.getValue());
					valuesToAdd.put("teacher_subject_td", tdtx.getValue());
					valuesToAdd.put("teacher_subject_tp", tptx.getValue());
					addALine(teacherSubjectHM, valuesToAdd);
					generateSubjectPanels(login2);
					generateTeacherPanels(subjectName2);
					if (!createdTupleList.contains(subjectId2+"/"+login2))
						createdTupleList.add(subjectId2+"/"+login2);
				}
				popUp.hide();
			}
		});
		
		panel.add(grid);
		panel.add(buttonPanel);
		
		popUp.add(panel);
		popUp.center();
		popUp.show();
	}
	
	/**
	 * Fonction fromLoginToName qui pour un login "adupont" donné retourne le nom "A. Dupont"
	 * @param login Identifiant de l'enseignant sous la forme adupont
	 * @return Une chaine de caractères de la forme A. Dupont
	 */
	public String fromLoginToName(String login){
		String result="";
		result+=login.charAt(0)+". "+login.charAt(1);
		result = result.toUpperCase();
		result+=login.substring(2);
		return result;
	}
	
	/**
	 * Fonction getName qui pour un login "adupont" donné retourne le nom "Dupont"
	 * @param login Identifiant de l'enseignant sous la forme adupont
	 * @return Une chaine de caractères de la forme Dupont
	 */
	public String getName(String login){
		String result="";
		result+=login.charAt(1);
		result = result.toUpperCase();
		result+=login.substring(2);
		return result;
	}
	
	/**
	 * Ajout d'une ligne dans un HashMap
	 * @param hm HasmMap cible
	 * @param values HashMap de valeurs à ajouter
	 */
	public void addALine(HashMap<String, String[]> hm, HashMap<String, String> values){
		int k=0;
		for (Iterator<String> i = hm.keySet().iterator() ; i.hasNext() ; ){
			String content = (String)i.next();
			String[] temp = new String[hm.get(content).length];
			temp = hm.get(content);
			String[] temp2 = new String[hm.get(content).length+1];
			for (int j = 0; j<temp.length; j++){
				temp2[j]=temp[j];
			}
			temp2[temp.length]=values.get(content);
			k++;
			hm.put(content, temp2);
	    }
	}
	
	/**
	 * Suppression d'une ligne d'index i dans un HashMap hm
	 * @param hm HashMap cible
	 * @param i Numéro de la ligne à supprimer.
	 * @return Le HashMap corrigé
	 */
	private HashMap<String, String[]> removeALine(HashMap<String, String[]> hm, int i) {
		HashMap<String, String[]> resultHM = new HashMap<String, String[]>();
		for (Iterator<String> it = hm.keySet().iterator(); it.hasNext();){
			String content = (String)it.next();
			String[] contents = new String[hm.get(content).length];
			String[] newContents = new String[hm.get(content).length-1];
			contents = hm.get(content);
			for (int j = 0; j<contents.length; j++){
				if (j<i){
					newContents[j]=contents[j];
				}
				else if (j>i){
					newContents[j-1]=contents[j];
				}
			}
			resultHM.put(content, newContents);
	    }
		return resultHM;
	}
	
	/**
	 * Modification d'une ligne d'un HashMap
	 * @param hm HashMap cible
	 * @param index Numéro de la ligne à modifier
	 * @param values HashMap des nouvelles valeurs
	 */
	public void updateALine(HashMap<String, String[]> hm, int index, HashMap<String, String> values){
		for (Iterator<String> i = hm.keySet().iterator() ; i.hasNext() ; ){
			String content = (String)i.next();
			String[] temp = new String[hm.get(content).length];
			temp=hm.get(content);
			temp[index]=values.get(content);
			hm.put(content, temp);
	    }
	}
	
	/**
	 * Fonction remainingHours qui calcule le nombre d'heures restantes de cm, td et tp
	 * à attribuer pour une matière à partir de son id.
	 * @param subjectId Identifiant de la matière
	 * @return Un tableau de double de la forme [reste CM; reste TD; reste TP]
	 */
	public double[] remainingHoursSubject(String subjectId){
		double[] result = new double[3];
		for (int i = 0; i<subjectHM.get("subject_id").length; i++){
			if (subjectHM.get("subject_id")[i].equals(subjectId)){
				result[0] = Double.parseDouble(subjectHM.get("subject_cm")[i]);
				result[1] = Double.parseDouble(subjectHM.get("subject_td")[i]);
				result[2] = Double.parseDouble(subjectHM.get("subject_tp")[i]);
			}
		}
		for (int i = 0; i<teacherSubjectHM.get("subject_id").length; i++){
			if (teacherSubjectHM.get("subject_id")[i].equals(subjectId)){
				result[0] -= Double.parseDouble(teacherSubjectHM.get("teacher_subject_cm")[i]);
				result[1] -= Double.parseDouble(teacherSubjectHM.get("teacher_subject_td")[i]);
				result[2] -= Double.parseDouble(teacherSubjectHM.get("teacher_subject_tp")[i]);
			}
		}
		return result;
	}
	
	/**
	 * Fonction remainingHoursTeacher qui calcule le nombre d'heures restantes en HEQTD
	 * @param login Identifiant de l'enseignant
	 * @return Un tableau de double de la forme [reste CM; reste TD; reste TP]
	 */
	public double[] remainingHoursTeacher(String login){
		double[] result = new double[3];
		double quota = 0.0;
		double temp0 = 0.0;
		double temp1 = 0.0;
		double temp2 = 0.0;
		
		for (int i = 0; i<teacherHM.get("teacher_login").length; i++){
			if (teacherHM.get("teacher_login")[i].equals(login)){
				quota = Double.parseDouble(teacherHM.get("teacher_quota")[i]);
			}
		}
		for (int i = 0; i<3; i++){
			result[i]=quota;
		}
		for (int i = 0; i<teacherSubjectHM.get("subject_id").length; i++){
			if (teacherSubjectHM.get("teacher_login")[i].equals(login)){
				temp0 += Double.parseDouble(teacherSubjectHM.get("teacher_subject_cm")[i]);
				temp1 += Double.parseDouble(teacherSubjectHM.get("teacher_subject_td")[i]);
				temp2 += Double.parseDouble(teacherSubjectHM.get("teacher_subject_tp")[i]);
			}
		}
		
		temp0 = temp0*1.833;
		temp2 = temp2*0.667;
		double resultTemp = temp0 + temp1 + temp2;
		result[0] = (result[0] - resultTemp)/1.833;
		result[1] = (result[1] - resultTemp);
		result[2] = (result[2] - resultTemp)/0.667;
		for (int i=0; i<3; i++){
			result[i] *= 100;
			result[i] = Math.round(result[i]);
			result[i] = result[i] / 100;
		}
		return result;
	}
	
	/**
	 * Fonction qui repère si le mot en HTML est entouré de la balise de mise en gras
	 * @param h code HTML
	 * @return true si le code contient < b> et false sinon
	 */
	public Boolean isBolded (HTML h){
		if (h.getHTML().startsWith("<b>")){
			return true;
		}
		else return false;
	}
	
	/*
	 * Fonctions nécessaires à la génération du code HTML avant exportation
	 */
	
	/**
	 * Méthode finale pour la génération du document en HTML
	 * @param courseId Identifiant de la filière
	 * @return Le code général et final du document généré.
	 */
	public String generateHTML(String courseId){
		String HTMLText = "";
		HTMLText += generateHeadHTML();
		HTMLText += generateCourseHTML(courseId);
		
		for (int i=0; i<subjectCourseHM.get("subject_id").length; i++){
			if (subjectCourseHM.get("course_id")[i].equals(courseId)){
				HTMLText += generateTable(subjectCourseHM.get("subject_id")[i]);
			}
		}
		
		HTMLText += generateFootHTML();
		
		return HTMLText;
	}
	
	/**
	 * Fonction qui génére toute l'entête du document
	 * @return l'entête du document
	 */
	public String generateHeadHTML(){
		String head = "" +
			"<html>" +
				"<head>" +
				"</head>" +
				"<body>" +
					"<table width=\"100%\" bgcolor=\"#A0CFEC\">" +
						"<th>FICHE ETAPE PREPARATOIRE</th>" +
					"</table>" +
					"<br />" +
					"<br />" +
					"<center>" +
					"<table rules=\"none\" frame=\"box\">" +
					//"<table rules=\"none\" border=\"0px\" frame=\"box\">" +
						"<tr>" +
							"<th align=\"right\">Composante</th>" +
							"<th width=\"75\" align=\"center\">902</th>" +
							"<th align=\"left\">SCIENCES ET TECHNIQUES</th>" +
						"</tr>" +
					"</table>" +
					"</center>" +
					"<br />";
		return head;
	}
	
	/**
	 * Fonction qui génère la description d'une filière
	 * @param courseId L'identifiant d'une filière
	 * @return Le code HTML
	 */
	public String generateCourseHTML(String courseId){
		String courseCode="";
		String courseName="";
		for (int i = 0; i<courseHM.get("course_id").length; i++){
			if (courseHM.get("course_id")[i].equals(courseId)){
				courseCode = courseHM.get("course_code")[i];
				courseName = courseHM.get("course_name")[i];
			}
		}
		String headCourse = "" +
				"<table rules=\"none\" frame=\"box\">" +
				//"<table rules=\"none\" border=\"0px\" frame=\"box\">" +
					"<tr>" +
						"<th width=\"70\" align=\"left\">Etape</th>" +
						"<th width=\"100\" align=\"left\">"+courseCode+"</th>" +
						"<th>"+courseName+"</th>" +
					"</tr>" +
				"</table width=\"100%\">" +
				"<br />";
		return headCourse;
	}
	
	/**
	 * Fonction qui génère un tableau pour une matière contenant les enseignants.
	 * @param subjectId Identifiant de la matière à générer
	 * @return Le code HTML du tableau
	 */
	public String generateTable(String subjectId){
		String table = "";
		String subjectCode = "";
		String subjectName = "";
		String subject_cm = "";
		String subject_group_cm = "";
		String subject_td = "";
		String subject_group_td = "";
		String subject_tp = "";
		String subject_group_tp = "";
		
		String teacherStatus = "";
		for (int i = 0; i<subjectHM.get("subject_id").length; i++){
			if (subjectHM.get("subject_id")[i].equals(subjectId)){
				subjectCode = subjectHM.get("subject_code")[i];
				subjectName = subjectHM.get("subject_name")[i];
				subject_cm = subjectHM.get("subject_cm")[i];
				subject_group_cm = subjectHM.get("subject_group_cm")[i];
				subject_td = subjectHM.get("subject_td")[i];
				subject_group_td = subjectHM.get("subject_group_td")[i];
				subject_tp = subjectHM.get("subject_tp")[i];
				subject_group_tp = subjectHM.get("subject_group_tp")[i];
				
			}
		}
		if (subjectCode.equals("")){
			return table;
		}
		table += "" +
			"<table>" +
				"<th width=\"200\"  align=\"left\">"+subjectCode+"</th>" +
				"<th align=\"left\">"+subjectName+"</th>" +
			"</table>" +
			"<table rules=\"none\" frame=\"box\">" +
			//"<table rules=\"none\" border=\"0px\" frame=\"box\">" +
				"<tr>" +
					"<th width=\"500\"></th>" +
					"<th width=\"75\">"+subject_cm+"x"+subject_group_cm+"</th>" +
					"<th width=\"75\">"+subject_td+"x"+subject_group_td+"</th>" +
					"<th width=\"75\">"+subject_tp+"x"+subject_group_tp+"</th>" +
				"</tr>" +
			"</table>" +
			"<table rules=\"all\" frame=\"box\">" +
				"<tr>" +
					"<td width=\"500\" align=\"left\">Enseignant</td>" +
					"<th width=\"75\">CM</th>" +
					"<th width=\"75\">TD</th>" +
					"<th width=\"75\">TP</th>" +
					"<th width=\"80\" align=\"left\">HEQTD</th>" +
					"<th width=\"75\" align=\"left\">Status</th>" +
				"</tr>";
		
		for (int i = 0; i<teacherSubjectHM.get("subject_id").length; i++){
			if (teacherSubjectHM.get("subject_id")[i].equals(subjectId)
					&& !(teacherSubjectHM.get("teacher_subject_cm")[i].equals("0")
					&& teacherSubjectHM.get("teacher_subject_td")[i].equals("0")
					&& teacherSubjectHM.get("teacher_subject_tp")[i].equals("0"))){
				for (int j = 0; j<teacherHM.get("teacher_login").length; j++){
					if (teacherHM.get("teacher_login")[j].equals(teacherSubjectHM.get("teacher_login")[i]))
						teacherStatus = teacherHM.get("teacher_status")[j];
				}
				
				table += "\n" +
				"<tr>" +"<td width=\"500\" align=\"left\">"+fromLoginToName(teacherSubjectHM.get("teacher_login")[i])+"</td>" +
					"<td width=\"75\" align=\"center\">"+teacherSubjectHM.get("teacher_subject_cm")[i]+"</th>" +
					"<td width=\"75\" align=\"center\">"+teacherSubjectHM.get("teacher_subject_td")[i]+"</th>" +
					"<td width=\"75\" align=\"center\">"+teacherSubjectHM.get("teacher_subject_tp")[i]+"</th>" +
					"<td width=\"80\" align=\"center\">"+calculateHEQTD(i)+"</th>" +
					"<td width=\"75\" align=\"center\">"+teacherStatus+"</th>" +
				"</tr>";
			}
		}
		table+="</table>" +
				"<br />";
		return table;
	}
	
	/**
	 * Fonction qui génère la fin du document HTML.
	 * @return la balise body
	 */
	public String generateFootHTML(){
		String result = "";
		result+= "\n</body>";
		return result;
	}
	
	/**
	 * Méthode qui calcule les 'heures equivalent TD' à partir d'un tuple de teacherSubjectHM
	 * @param i Index du HashMap teacherSujectHM
	 * @return La somme des toutes les heures.
	 */
	public double calculateHEQTD(int i){
		double cm = Double.parseDouble(teacherSubjectHM.get("teacher_subject_cm")[i]);
		double td = Double.parseDouble(teacherSubjectHM.get("teacher_subject_td")[i]);
		double tp = Double.parseDouble(teacherSubjectHM.get("teacher_subject_tp")[i]);
		double result = 0.0;
		result+= cm*1.833;
		result+= td;
		result+= tp*0.667;
		
		//Arrondi à deux chiffres après la virgules
		result *= 100;
		result = Math.round(result);
		result = result / 100;
		
		return result;
	}
	
	/**
	 * Méthode qui convertit un nombre d'heures en HEQTD en heures CM, TD et TP
	 * @param hours un nombre d'heure exprimé en HEQTD
	 * @return Un tableau de la forme [heures CM; heures TD; heure TP]
	 */
	public double[] calculateHoursFromHEQTD(double hours){
		double[] result = new double[3];
		result[0]= hours/1.833;
		result[1]= hours;
		result[2]= hours/0.667;
		
		//Arrondi à deux chiffres après la virgules
		for (int i=0; i<result.length; i++){
			result[i] *= 100;
			result[i] = Math.round(result[i]);
			result[i] = result[i] / 100;
		}
		return result;
	}
	
	/**
	 * Fonction pour la modification des dimensions du module en cas de changement des dimensions de
	 * fenêtre principale
	 */
	public void onResize(){
		mainPanel.setSize(Window.getClientWidth()*3/4+"px", Window.getClientHeight()+"px");
	}
	
	/**
	 * Récupération du nom de la matière
	 * @param subjectTeacher Chaîne de caractères du type Anglais/adupont 
	 * @return Le nom de la matière
	 */
	public String getFirst(String subjectTeacher){
		int index = subjectTeacher.indexOf("/");
		String subject = subjectTeacher.substring(0, index);
		return subject;
	}
	
	/**
	 * Récupération du nom de l'enseignant
	 * @param subjectTeacher Chaîne de caractères du type Anglais/adupont 
	 * @return Le nom de l'enseignant
	 */
	public String getLast(String subjectTeacher){
		int index = subjectTeacher.indexOf("/");
		String login = subjectTeacher.substring(index+1, subjectTeacher.length());
		return login;
	}
	
	/**
	 * Modification de la base de données en prenant en compte les changements effectués
	 * lors de la simulation.
	 */
	public void updateDB(){
		//Ajouts des tuples créés
		for (int i=0; i<createdTupleList.size(); i++){
			String subjectId = getFirst(createdTupleList.get(i));
			String login = getLast(createdTupleList.get(i));
			double cm = 0.0;
			double td = 0.0;
			double tp = 0.0;
			
			for (int j=0; j<teacherSubjectHM.get("teacher_login").length; j++){
				if (teacherSubjectHM.get("teacher_login")[j].equals(login)
						&& teacherSubjectHM.get("subject_id")[j].equals(subjectId)){
					cm = Double.parseDouble(teacherSubjectHM.get("teacher_subject_cm")[j]);
					td = Double.parseDouble(teacherSubjectHM.get("teacher_subject_td")[j]);
					tp = Double.parseDouble(teacherSubjectHM.get("teacher_subject_tp")[j]);
				}
			}
			String query = "INSERT INTO teacher_subject (subject_id,teacher_login," +
					"teacher_subject_cm,teacher_subject_td,teacher_subject_tp)" +
					" VALUES ('"+subjectId+"','"+login+"',"+cm+","+td+","+tp+");";
			dataService.select(query,new AsyncCallback<HashMap<String,String[]>>(){
				public void onFailure(Throwable caught){
					Window.alert("Erreur lors de la mise à jour de la DB - ajout d'un tuple");				
				}
				public void onSuccess(HashMap<String, String[]> result){
				}
			});
		}
		
		//Mise à jour des tuples modifiés
		for (int i =0; i<modifiedTupleList.size(); i++){
			String subjectId = getFirst(createdTupleList.get(i));
			String login = getLast(createdTupleList.get(i));
			double cm = 0.0;
			double td = 0.0;
			double tp = 0.0;
			String cmTemp = "";
			String tdTemp = "";
			String tpTemp = "";
			
			for (int j=0; j<teacherSubjectHM.get("teacher_login").length; j++){
				if (teacherSubjectHM.get("teacher_login")[j].equals(login)
						&& teacherSubjectHM.get("subject_id")[j].equals(subjectId)){
					cmTemp = teacherSubjectHM.get("teacher_subject_cm")[j];
					tdTemp = teacherSubjectHM.get("teacher_subject_td")[j];
					tpTemp = teacherSubjectHM.get("teacher_subject_tp")[j];
				}
				if (!cmTemp.equals("") && !tdTemp.equals("") && !tpTemp.equals("")){
					cm = Double.parseDouble(cmTemp);
					td = Double.parseDouble(tdTemp);
					tp = Double.parseDouble(tpTemp);
					
					String query = "UPDATE teacher_subject SET teacher_subject_cm='"+cm+"'," +
							"teacher_subject_td='"+td+"',teacher_subject_tp='"+tp+"'" +
									"WHERE teacher_login = '"+login+"' AND subject_id='"+subjectId+"';";
					dataService.select(query,new AsyncCallback<HashMap<String,String[]>>(){
						public void onFailure(Throwable caught){
							Window.alert("Erreur lors de la mise à jour de la DB - mise à jour d'un tuple");				
						}
						public void onSuccess(HashMap<String, String[]> result){
							
						}
					});
				}
				//Suppression des données dans la base
				else{
					String query = "DELETE FROM teacher_subject" +
							"WHERE teacher_login = '"+login+"' AND subject_id='"+subjectId+"';";
					dataService.select(query,new AsyncCallback<HashMap<String,String[]>>(){
						public void onFailure(Throwable caught){
							Window.alert("Erreur lors de la mise à jour de la DB - mise à jour d'un tuple");				
						}
						public void onSuccess(HashMap<String, String[]> result){
							
						}
					});
				}
			}
		}
		dataBaseLoad();
	}
	

	
	public void exportation(final String courseId){
		String courseName = "Fiche - ";
		for (int i=0; i<courseHM.get("course_id").length; i++){
			if (courseHM.get("course_id")[i].equals(courseId)){
				courseName+=courseHM.get("course_name")[i];
			}
		}
		final String courseNameFinal=courseName;
		final Date d = new Date();
		templatesFunc.saveDoc(courseName, generateHTML(courseId), d.getTime(), s.get("login"), new AsyncCallback<String>(){
			public void onFailure(Throwable caught){
				Window.alert("Document save : "+SERVER_ERROR);
			}
			
			public void onSuccess(String result){
				String r="insert into template(template_name,template_path,template_date,template_visibility) " +
				"values ('"+courseNameFinal+"','"+result+"','"+d.getTime()+"','"+1+"')";
				dataService.insert(r, new AsyncCallback<Integer>(){
					public void onFailure(Throwable caught){	
									Window.alert("Data insert : "+SERVER_ERROR);
					}
					public void onSuccess(Integer result){
						String r= "insert into teacher_template values ('"+result+"','"+s.get("teacher_login")+"')";
						dataService.insert(r, new AsyncCallback<Integer>(){
							public void onFailure(Throwable caught){
								Window.alert("Data insert : "+SERVER_ERROR);
							}
							public void onSuccess(Integer result){
							}
						});
					}
				});
			}
		});
		Window.alert("Le document "+courseName+" a été rajouté parmi vos templates");
	}
	
	/**
	 * Fonction qui réinitialise le module en effaçant les modifications apportés par la simulation.
	 */
	public void refresh(){
		subjectList = new ArrayList<String>();
		teacherList = new ArrayList<String>();
		createdTupleList = new ArrayList<String>(); 
		modifiedTupleList = new ArrayList<String>();

		firstView = false;
		firstViewSubject = false;
		firstViewTeacher = false;
		dataBaseLoad();
		generateCourses();
		generateTeachers();
	}
}
